package com.modular.iot.opt;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.c.opt.ComOpt;
import com.ToolOpt;
import com.modular.iot.bean.ThingsAttributeDo;
import com.modular.iot.bean.ThingsProductDo;
import com.modular.iot.bo.IotAttribute;
import com.modular.iot.bo.IotModelBo;
import ntd.util.ToolCache;
import ntd.util.ToolLock;
import ntd.util.config.common.enums.EnumStatus;
import ntd.util.config.common.exception.ComException;
import ntd.util.modular.things.entity.Device;
import ntd.util.modular.things.entity.Service;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 设备操作
 */
public class OptIotDevice extends ComOpt<Device> {

    public OptIotDevice() {
        super("things_device");
    }

    public Device getByCode(String code) {
        if (StrUtil.isBlank(code)) {
            throw new ComException("获取设备信息，code不能为空!!!");
        }
        String key = "device-code-" + code;
        Device device = ToolCache.get(key);
        if (ObjectUtil.isNull(device)) {
            device = query().eq("code", code).getBean();
            ToolCache.set(key, device, 60000);
        }
        return device;
    }

    /**
     * 初始化设备信息 - 如果设备不存在则使用code新建设备
     * @param code
     * @return
     */
    public Device initDevice(String code, String ip) {
        if (StrUtil.isBlank(code)) {
            throw new ComException("初始化设备信息，code不能为空!!!");
        }
        AtomicReference<Device> device = new AtomicReference<>();
        ToolLock.lockRun("init-device-" + code, () -> {
            device.set(ObjectUtil.defaultIfNull(getByCode(code), () -> {
                Device tDevice = new Device();
                tDevice.setCode(code);
                tDevice.setName(code);
                tDevice.setProductId("1");
                tDevice.setNote("系统自动添加设备");
                return tDevice;
            }));
            device.get().setLastConnTime(LocalDateTimeUtil.now());
            device.get().setLastConnIp(Opt.ofBlankAble(ip).orElse("0.0.0.0"));
            device.get().setStatus(EnumStatus.ENABLE.getVal());
            // 保存并设置回传id
            device.get().setId(syncBean(device.get()));
        });
        // 返回数据
        return device.get();
    }

    /**
     * 初始化设备信息
     * @return
     */
    public Device initDevice(IotModelBo iotModelBo) {
        if (StrUtil.isBlank(iotModelBo.getCode())) {
            throw new ComException("初始化设备信息，code不能为空!!!");
        }
        Device device = ObjectUtil.defaultIfNull(getBean(query().eq("code", iotModelBo.getCode())), () -> {
            Device tDevice = new Device();
            tDevice.setCode(iotModelBo.getCode());
            tDevice.setName(iotModelBo.getName());
            tDevice.setProductId("1");
            tDevice.setNote("系统自动添加设备");
            return tDevice;
        });
        device.setStatus(iotModelBo.getStatus());
        device.setLastConnTime(iotModelBo.getLastConnTime());
        device.setLastConnIp(iotModelBo.getLastConnIp());
        // 保存并设置回传id
        device.setId(syncBean(device));
        return device;
    }

    /**
     * 设备离线
     * @param code
     */
    public void offLine(String code) {
        if (StrUtil.isBlank(code)) {
            return;
        }
        Device device = getBean(query().eq("code", code));
        if (ObjectUtil.isNotNull(device)) {
            device.setStatus(EnumStatus.DISABLE.getVal());
            syncBean(device);
        } else {
            StaticLog.error("找不到设备[{}]", code);
        }
    }

    /**
     * 获取设备的物模型信息
     * @param code
     * @return
     */
    public IotModelBo iotModel(String code) {
        Device device = getByCode(code);
        if (ObjectUtil.isNull(device)) {
            return null;
        }
        IotModelBo iotModelBo = IotModelBo.transform(device);
        // 封装设备属性
        ThingsProductDo productDo = ToolOpt.OPT_T_PRODUCT.getBeanById(device.getProductId());
        Opt.ofNullable(productDo).ifPresent(thingsProductDo -> {
            List<ThingsAttributeDo> attributeDos = ToolOpt.OPT_T_ATTRIBUTE.query().eq("product_id", thingsProductDo.getId()).eq("is_shadow", "2").listBean();
            List<ThingsAttributeDo> deviceAttributes = ToolOpt.OPT_T_ATTRIBUTE.query().eq("device_id", device.getId()).eq("is_shadow", "2").listBean();
            List<String> codes = CollStreamUtil.toList(deviceAttributes, ThingsAttributeDo::getCode);
            CollUtil.filter(attributeDos, thingsAttributeDo -> !codes.contains(thingsAttributeDo.getCode()));
            for (ThingsAttributeDo thingsAttributeDo : CollUtil.unionAll(attributeDos, deviceAttributes)) {
                iotModelBo.addAttribute(IotAttribute.transform(thingsAttributeDo));
            }
        });

        // 封装设备服务
        if (JSONUtil.isTypeJSONArray(productDo.getServices())) {
            List<Service> services = ToolOpt.OPT_T_SERVICE.query().in("id", JSONUtil.toList(productDo.getServices(), String.class)).listBean();
            iotModelBo.setServices(services);
        }

        return iotModelBo;
    }

}
